/**
 * 
 */
package jmai.evaluator;

import java.util.ArrayList;

import jmai.parser.Driver;
import jmai.scanner.ASTTree;

/**
 * @author Jean-Pierre
 *
 */
public class Evaluator {
	
	ArrayList<String> input = null;
	Boolean debug = false;
	Boolean dfa = false;
	Boolean nfa = false;
	
	public Evaluator(String input, Boolean debug, Boolean dfa, Boolean nfa) {
		
		if(input.endsWith(".data")) {
			this.input = Helper.input(input);
		} else {
			this.input = new ArrayList<String>(1);
			this.input.add(input);
		}
			
		this.nfa = nfa;
		this.dfa = dfa;
		this.debug = debug;
	}
	
	public Boolean validate(String regex, String input) {
		//Boolean isValid = false;
		
		//String regex = ast.GetRegEx(j);
		regex = regex.replace('+', '$');
		
		Driver driver = new Driver(regex);
		String[][] adjM = driver.getDFA();
		String[][] nfaAdjM = driver.getNFA();
		
		int index = nfaAdjM[0].length;
		String nfaAcceptState = nfaAdjM[0][index-1];
		
//		if(nfa)
//			driver.printNFAStruct();
//		
//		if(dfa)
//			driver.printDFAStruct();
		
		ArrayList<String> stateList = new ArrayList<String>(adjM[0].length - 1);
		for(int i=1; i<adjM[0].length; i++) {
			stateList.add(adjM[0][i]);
		}
		
		char[] tmp = input.toCharArray();
		
		int state = 1;
		
		//System.out.println(adjM[state].length);
		
		for(int i = 0; i< tmp.length; i++) {
			Boolean foundT = false;
			
			for(int j = 1; j< adjM[state].length; j++) {
				char[] chr = { tmp[i] };
				//System.out.println(state + "," + adjM[state][j]);
				
				if(adjM[state][j] != null && adjM[state][j].equals(new String(chr))) {
					foundT = true;
					state = stateList.indexOf(adjM[0][j]) + 1;
				}
			}
			
			if(!foundT)
				return false;
			
		}
		
		if(!adjM[state][0].contains(nfaAcceptState))
			return false;
		
		// take in a regex and try to step through
		// the DFA (adjacency matrix) one character
		// at a time.
		
		// if finish in ACCEPT state, return true
		// else false
		
		return true;
	}
	
	public void walk(ASTTree ast) {
		
		int i = 1, e = ast.GetNumberOfPairs();
		
		if(ast.GetHasBeginAction()) {
			Functions.call("print", ast.GetFirstParameter(1, 1), null, null, debug);
		}
		
		if(ast.GetHasBeginAction()) {
			i = 2;
		}
		
		if(ast.GetHasEndAction()) {
			e = ast.GetNumberOfPairs() - 1;
		}
		
		for(int j = i; j<=e; j++) {
			
			if(!ast.GetPairType(j).equals("No RegEx")) {
				String regex = ast.GetRegEx(j);
				regex = regex.replace('+', '$');
				Driver driver = new Driver(regex);
				if(nfa)
					driver.printNFAStruct();
				if(dfa)
					driver.printDFAStruct();
			}	
			
			for(int k = 0; k<input.size(); k++) {
				
				if(ast.GetPairType(j).equals("No RegEx") || validate(ast.GetRegEx(j), input.get(k))) {
				
					for(int l = 1; l<=ast.GetNumberOfActions(j); l++) {
						if(ast.GetAction(j, l).equals("print")) {
							if(ast.GetFirstParameter(j, l).equals("LINE"))
								Functions.call("print", input.get(k), null, null, debug);
							else
								Functions.call("print", ast.GetFirstParameter(j,l), null, null, debug);
						} else {
							if(ast.GetSecondParameter(j, l) != null) {
								input.set(k, Functions.call(ast.GetAction(j, l), input.get(k), ast.GetFirstParameter(j, l), ast.GetSecondParameter(j, l), debug));
							} else {
								input.set(k, Functions.call(ast.GetAction(j, l), input.get(k), ast.GetFirstParameter(j, l), null, debug));
							}
						}
					}
				}
			}
		}
		
		if(ast.GetHasEndAction()) {
			Functions.call("print", ast.GetFirstParameter(ast.GetNumberOfPairs(), 1), null, null, debug);
		}
		
		// traverse the AST
		
		// check if BEGIN exists, if so, execute
		
		// for each pattern
			// check if regex matches pattern (validate)
			// if so, execute all action : parameter pairs
				// substring, insert, print, remove, replace
		
		// check if END exists, if so, execute	
		
		return;
	}
}
